package adventure.placeable;

import adventure.misc.Currency;
import adventure.misc.CurrencyImp;
import colour.ColourUtil;
import java.util.ArrayList;
import player.Player;

/**
 *
 * @author Michael Hanns
 *
 */
public class MobileImp extends PlaceableImp implements Mobile, MobileEdit, Fightable, Cloneable {

    private int x;
    private int y;
    private int z;
    private int level;
    private int maxHealth;
    private int health;
    private int attack;
    private int defence;
    private int speed;
    private int luck;
    private boolean aggro;
    private boolean dead;
    private boolean immortal;
    private boolean vendor;
    private double vendorMod;
    private Currency currencyType;
    private int currencyAmount;
    private ArrayList<Item> inventory;
    private ArrayList<Player> aggroPlayers;
    private ArrayList<Fightable> inCombatWith;

    public MobileImp() {
        super();

        level = 0;

        maxHealth = 1;
        health = 1;

        attack = 0;
        defence = 0;
        speed = 0;
        luck = 0;

        aggro = false;
        dead = false;
        immortal = false;
        vendor = false;
        vendorMod = 0;

        currencyType = new CurrencyImp();
        currencyAmount = 0;
        inventory = new ArrayList<Item>();

        aggroPlayers = new ArrayList<Player>();
        inCombatWith = new ArrayList<Fightable>();
    }

    public MobileImp(int id) {
        super(id);

        level = 0;

        maxHealth = 1;
        health = 1;

        attack = 0;
        defence = 0;
        speed = 0;
        luck = 0;

        aggro = false;
        dead = false;
        immortal = false;
        vendor = false;
        vendorMod = 0;

        currencyType = new CurrencyImp();
        currencyAmount = 0;
        inventory = new ArrayList<Item>();

        aggroPlayers = new ArrayList<Player>();
        inCombatWith = new ArrayList<Fightable>();
    }

    @Override
    public void setCurrencyType(Currency type) {
        this.currencyType = type;
    }

    @Override
    public void setX(int newx) {
        x = newx;
    }

    @Override
    public void setY(int newy) {
        y = newy;
    }

    @Override
    public void setZ(int newz) {
        z = newz;
    }

    @Override
    public void setLevel(int level) {
        this.level = level;
    }

    @Override
    public void setMaxHealth(int hp) {
        maxHealth = hp;
        health = hp;
    }

    @Override
    public void modifyHealth(int mod) {
        health = health + mod;
        if (health <= 0) {
            dead = true;
        } else if (health > maxHealth) {
            this.health = this.maxHealth;
        }
    }

    @Override
    public void setAttack(int val) {
        attack = val;
    }

    @Override
    public void setDefence(int val) {
        defence = val;
    }

    @Override
    public void setSpeed(int val) {
        speed = val;
    }

    @Override
    public void setLuck(int val) {
        luck = val;
    }

    @Override
    public void setAggro(boolean val) {
        aggro = val;
    }

    @Override
    public void setAggro(Player p) {
        for (int c = 0; c < aggroPlayers.size(); c++) {
            if (aggroPlayers.get(c).getID() == p.getID()) {
                return;
            }
        }
        aggroPlayers.add(p);
    }

    @Override
    public void setDead(boolean val) {
        if (val) {
            health = 0;
            dead = true;
        } else {
            health = maxHealth;
            dead = false;
        }
    }

    @Override
    public void setImmortal(boolean val) {
        immortal = val;
    }

    @Override
    public void setVendor(boolean val) {
        vendor = val;
    }

    @Override
    public void setVendorModifier(double val) {
        vendorMod = val;
    }

    @Override
    public void setCurrencyAmount(int val) {
        currencyAmount = val;
    }

    @Override
    public boolean isPlayer() {
        return false;
    }

    @Override
    public int x() {
        return x;
    }

    @Override
    public int y() {
        return y;
    }

    @Override
    public int z() {
        return z;
    }

    @Override
    public String getName() {
        if (!dead) {
            return super.getName();
        }
        return "corpse of " + super.getName();
    }

    @Override
    public String getAliveName() {
        return super.getName();
    }

    @Override
    public String getHealthStatus() {
        if (health == maxHealth) {
            return ColourUtil.colourise(super.getName(), ColourUtil.mobile) + " appears to be in perfect health.";
        } else if (health > maxHealth * 0.9) {
            return ColourUtil.colourise(super.getName(), ColourUtil.mobile) + " has a couple of scratches.";
        } else if (health > maxHealth * 0.8) {
            return ColourUtil.colourise(super.getName(), ColourUtil.mobile) + " is looking worse for the wear.";
        } else if (health > maxHealth * 0.6) {
            return ColourUtil.colourise(super.getName(), ColourUtil.mobile) + " is bleeding heavily.";
        } else if (health > maxHealth * 0.4) {
            return ColourUtil.colourise(super.getName(), ColourUtil.mobile) + " is mortally wounded!";
        } else if (health > maxHealth * 0.2) {
            return ColourUtil.colourise(super.getName(), ColourUtil.mobile) + " is in crippling pain!";
        } else {
            return ColourUtil.colourise(super.getName(), ColourUtil.mobile) + " feels the cold touch of death!";
        }
    }

    @Override
    public String getDescription() {
        System.out.println(currencyAmount);
        if (!dead) {
            return super.getDescription().replace(super.getName(), ColourUtil.colourise(super.getName(), ColourUtil.mobile));
        } else {
            String desc = "It's the rotting remains of what was once "
                    + ColourUtil.colourise(super.getName(), ColourUtil.mobile) + ".";
            if (inventory.size() > 0) {
                desc = desc.concat("\nContains:");
                for (int c = 0; c < inventory.size(); c++) {
                    desc = desc.concat("\n".concat(
                            ColourUtil.colourise(inventory.get(c).getName(), ColourUtil.item)));
                }
                if (currencyAmount > 0) {
                    String currencyName;
                    if (currencyAmount > 1) {
                        currencyName = currencyAmount + " " + currencyType.getPlural();
                    } else {
                        currencyName = "a " + currencyType.getSingular();
                    }

                    desc = desc.concat("\n".concat(
                            ColourUtil.colourise(currencyName, ColourUtil.currency)));
                }
            } else if (currencyAmount > 0) {
                String currencyName;
                if (currencyAmount > 1) {
                    currencyName = currencyAmount + " " + currencyType.getPlural();
                } else {
                    currencyName = "a " + currencyType.getSingular();
                }

                desc = desc.concat("\nContains:\n".concat(
                        ColourUtil.colourise(currencyName, ColourUtil.currency)));
            }

            return desc;
        }
    }

//    @Override
//    public String getDescription(Currency currencyName) {
//        if (!dead) {
//            return super.getDescription().replace(super.getName(), Colour.colourise(super.getName(), Colour.mobile));
//        } else {
//            String desc = "It's the rotting remains of what was once "
//                    + Colour.colourise(super.getName(), Colour.mobile) + ".";
//            if (inventory.size() > 0) {
//                desc = desc.concat("\nContains:");
//                for (int c = 0; c < inventory.size(); c++) {
//                    desc = desc.concat("\n".concat(
//                            Colour.colourise(inventory.get(c).getName(), Colour.cyan)));
//                }
//                if (currency > 1) {
//                    desc = desc.concat("\n".concat(
//                            Colour.colourise(String.valueOf(currency).concat(" ").concat(currencyName.getPlural()), Colour.yellow)));
//                } else if (currency > 0) {
//                    desc = desc.concat("\n".concat(
//                            Colour.colourise(String.valueOf(currency).concat(" ").concat(currencyName.getSingular()), Colour.yellow)));
//                }
//            } else if (currency > 1) {
//                desc = desc.concat("\n".concat(
//                        Colour.colourise(String.valueOf(currency).concat(" ").concat(currencyName.getPlural()), Colour.yellow)));
//            } else if (currency > 0) {
//                desc = desc.concat("\n".concat(
//                        Colour.colourise(String.valueOf(currency).concat(" ").concat(currencyName.getSingular()), Colour.yellow)));
//            }
//
//            return desc;
//        }
//    }
    @Override
    public String getAliveDescription() {
        return super.getDescription();
    }

    @Override
    public int getLevel() {
        return level;
    }

    @Override
    public int getMaxHealth() {
        return maxHealth;
    }

    @Override
    public int getAttack() {
        return attack;
    }

    @Override
    public int getDefence() {
        return defence;
    }

    @Override
    public int getIntelligence() {
        return 10;
    }

    @Override
    public int getSpeed() {
        return speed;
    }

    @Override
    public int getLuck() {
        return luck;
    }

    @Override
    public int getWeaponMod() {
        return 0;
    }

    @Override
    public int getOffhandMod() {
        return 0;
    }

    @Override
    public int getHelmMod() {
        return 0;
    }

    @Override
    public int getChestMod() {
        return 0;
    }

    @Override
    public int getBootsMod() {
        return 0;
    }

    @Override
    public boolean isAggro() {
        return aggro;
    }

    @Override
    public boolean isAggro(int p) {
        for (int c = 0; c < aggroPlayers.size(); c++) {
            if (aggroPlayers.get(c).getID() == p) {
                return true;
            }
        }
        return aggro;
    }

    @Override
    public boolean isDead() {
        return dead;
    }

    @Override
    public boolean isImmortal() {
        return immortal;
    }

    @Override
    public boolean isVendor() {
        return vendor;
    }

    @Override
    public double getVendorModifier() {
        return vendorMod;
    }

    @Override
    public boolean hasHealingPotion() {
        for (int c = 0; c < inventory.size(); c++) {
            if (inventory.get(c).getItemType().equalsIgnoreCase("HPOTION")) {
                return true;
            }
        }
        return false;
    }

    @Override
    public String drinkHealingPotion() {
        for (int c = 0; c < inventory.size(); c++) {
            if (inventory.get(c).getItemType().equalsIgnoreCase("HPOTION")) {
                health = Math.min(health += inventory.get(c).getModifier(), maxHealth);
                String success = getName() + " quaffs " + inventory.get(c).getName()
                        + " and regains health!";
                inventory.get(c).useOnce();
                return success;
            }
        }
        return getName() + " has no potions to quaff!";
    }

    @Override
    public boolean isNearlyDead() {
        if (health < (maxHealth * 0.15)) {
            return true;
        }
        return false;
    }

    @Override
    public boolean attack(Fightable target) {
        if (inCombatWith.size() > 0 && inCombatWith.get(0).equals(target)) {
            return false;
        }

        if (!target.isDead()) {
            inCombatWith.remove((Fightable) target);
            inCombatWith.add(0, (Fightable) target);
            target.attack((Fightable) this);
            if (target.isPlayer()) {
                setAggro((Player) target);
            }
            return true;
        }
        return false;
    }

    @Override
    public boolean isFighting(int id) {
        for (int c = 0; c < inCombatWith.size(); c++) {
            if (((Player) inCombatWith.get(c)).getID() == id) {
                return true;
            }
        }
        return false;
    }

    @Override
    public void stopFighting(Player victim) {
        inCombatWith.remove(victim);
    }

    @Override
    public int getCurrencyContents() {
        return currencyAmount;
    }

    @Override
    public void addInventoryItem(Item i) {
        if (i.getID() != 0) {
            inventory.add(i);
        }
    }

    @Override
    public void emptyInventory() {
        inventory = new ArrayList<Item>();
    }

    @Override
    public Item getInventoryItem(int x) {
        if (inventory.isEmpty() || x >= inventory.size()) {
            return (new ItemImp());
        } else {
            Item returnItem = inventory.get(x);
            return returnItem;
        }
    }

    @Override
    public Item takeInventoryItem(int x) {
        if (inventory.isEmpty() || x >= inventory.size()) {
            return (new ItemImp());
        } else {
            Item returnItem = inventory.get(x);
            inventory.remove(x);
            return returnItem;
        }
    }

    @Override
    public Item takeInventoryItem(Item item) {
        if (inventory.isEmpty()) {
            return (new ItemImp());
        } else {
            for (int x = 0; x < inventory.size(); x++) {
                if (inventory.get(x).equals(item)) {
                    inventory.remove(x);
                    return item;
                }
            }

            return new ItemImp();
        }
    }

    @Override
    public int takeCurrencyAmount(int quant) {
        if (currencyAmount >= quant) {
            currencyAmount -= quant;
            return quant;
        } else {
            int taken = currencyAmount;
            currencyAmount = 0;
            return taken;
        }
    }

    @Override
    public void addCurrencyAmount(int quant) {
        currencyAmount += quant;
    }

    @Override
    public Fightable[] getLocalTargets() {
        if (inCombatWith.size() > 0) {
            Fightable[] targets = new Fightable[inCombatWith.size()];
            for (int c = 0; c < targets.length; c++) {
                targets[c] = inCombatWith.get(c);
            }
            return targets;
        }
        return new Fightable[0];
    }

    @Override
    public Mobile cloneThis() {
        Mobile newClone = new MobileImp();
        try {
            newClone = (MobileImp) this.clone();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return newClone;
    }

    @Override
    public Object clone() {
        try {
            Object clone = super.clone();
            ((MobileImp) clone).inventory = new ArrayList<Item>();

            for (int c = 0; c < inventory.size(); c++) {
                ((MobileImp) clone).inventory.add(inventory.get(c).cloneThis());
            }

            ((MobileImp) clone).currencyType = this.currencyType;

            ((MobileImp) clone).aggroPlayers = new ArrayList<Player>();
            ((MobileImp) clone).inCombatWith = new ArrayList<Fightable>();

            return clone;
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
    }
}
